import math
import time
import sys

sys.path.append("../")  # noqa
from bson import ObjectId
from pymongo import UpdateOne, MongoClient
from collections import defaultdict

from tqdm import tqdm
from config import col_alumni, col_institution, col_register, col_activity, col_top11
from config import settings
from task_utils.util_mapping import query_year

client = MongoClient(settings.dsn)
col_inst = col_institution
activity_col = col_activity
institution_col = col_institution
activity_register_col = col_register
col_person = col_alumni
col_top11 = col_top11


def is_high_position(person_id, person_position_dict, position):
    for item in person_position_dict[ObjectId(person_id)]:
        if item and ((item in position and "副" not in item) or ("正高级" in item)):
            return True
        else:
            if person_position_dict[ObjectId(person_id)][-1] == item:
                return False
            else:
                continue


def cal_oindex_high(person_position_dict, org_year_activity_dict, org_list, position):
    """
    计算某个机构当年联系的人才中
    正高级职称的比例Q=正高级职称的人数/总人数。然后，在11个有联系人才要求的内部直属单位中，
    选择Q不是0的全部机构，设置当前机构的Q值为“Q当前机构”，取Q最大的机构Qmax,取Q最小的机构Qmin,
    然后计算比值H=10*（“Q当前机构”-Qmin）/ (Qmax-Qmin)，
    """
    high_position_person = [
        x for x in person_position_dict.keys() if is_high_position(x, person_position_dict, position)
    ]
    year_org_qvalue_dict = defaultdict(dict)
    for org_id, year_act_dict in org_year_activity_dict.items():
        for k, v in year_act_dict.items():
            persons = list(
                set(
                    [
                        x["person_id"]
                        for x in activity_register_col.find({"activity_id": {"$in": v}}, {"person_id": 1, "_id": 0})
                    ]
                )
            )
            persons_h = [x for x in persons if x in high_position_person]
            if not persons:
                year_org_qvalue_dict[k][org_id] = 0
            else:
                year_org_qvalue_dict[k][org_id] = len(persons_h) / len(persons)
    radar_dict = defaultdict(list)
    for k, v in year_org_qvalue_dict.items():
        h_position_num_list = [x for x in v.values() if x > 0]
        min_h = min(h_position_num_list)
        max_h = max(h_position_num_list)
        for k1, v1 in v.items():
            try:
                oindex_high = round(max(2, 10 * (v1 - min_h) / (max_h - min_h)), 2)
            except ZeroDivisionError:
                oindex_high = 10
            radar_dict[k1].append({"year": k, "oindex_high": oindex_high})
        for org in org_list:
            if org not in radar_dict:
                radar_dict[org].append({"year": k, "oindex_high": 0})
    return radar_dict


def cal_oindex_deep(radar_dict, org_year_activity_dict):
    """
    计算某个机构组织的当年的全部活动总数A
    重要性的总分I，其中每个常规1分，重点2分，重大3分，默认是1
    然后得到重要性均分D=I/A，
    选择A不是0的全部机构，设置当前机构的D值为“D当前机构”，取D最大的机构Dmax,取D最小的机构Dmin,然后计算比值S=10*(D当前机构-Dmin)/ (Dmax-Dmin)，
    """
    activity_role_score = defaultdict(lambda: 1)
    activity_role_score.update({"常规": 1, "重点": 2, "重大": 3, "": 1, None: 1})
    year_org_dvalue_dict = defaultdict(dict)
    for org_id, year_act_dict in org_year_activity_dict.items():
        sum_dscore = 0
        for k, v in year_act_dict.items():
            for act_id in v:
                act_info = activity_col.find_one({"_id": act_id})
                sum_dscore += activity_role_score[act_info.get("importance_of_activities")]
            year_org_dvalue_dict[k][org_id] = sum_dscore / len(v)

    for k, v in year_org_dvalue_dict.items():
        d_value_list = [x for x in v.values() if x > 0]
        min_d = min(d_value_list)
        max_d = max(d_value_list)
        for k1, v1 in v.items():
            try:
                oindex_deep = round(max(2, 10 * (v1 - min_d) / (max_d - min_d)), 2)
            except ZeroDivisionError:
                oindex_deep = 10
            for item in radar_dict[k1]:
                if k == item["year"]:
                    item.update({"oindex_deep": oindex_deep})

    for k, v in radar_dict.items():
        for item in v:
            if "oindex_deep" not in item:
                item.update({"oindex_deep": 0})
    return radar_dict


def generate_person_position_dict():
    person_position_dict = {}
    person_data = col_person.find({}, {"professional_titles": 1})
    person_data = list(person_data)
    for item in person_data:
        if item.get("professional_titles", []):
            person_position_dict[item["_id"]] = item.get("professional_titles", [])
        else:
            person_position_dict[item["_id"]] = []
    return person_position_dict


def cal_oindex_tight(radar_dict, org_year_activity_dict):
    """
    计算某个机构联系人才的人数M
    计算某个机构联系人才的人次N
    则人均参与该机构组织活动的次数：J=M/N
    选择N不是0的全部机构，设置当前机构的J值为“J当前机构”，取J最大的机构Jmax,取J最小的机构Jmin,然后计算比值JM=10*(J当前机构-Jmin)/ (Jmax-Jmin)，
    """
    year_org_tvalue_dict = defaultdict(dict)
    for org_id, year_act_dict in org_year_activity_dict.items():
        for k, v in year_act_dict.items():
            persons = [
                x["person_id"]
                for x in activity_register_col.find(
                    {"activity_id": {"$in": v}, "is_attended": True}, {"person_id": 1, "_id": 0}
                )
            ]
            print(len(persons), len(set(persons)))
            try:
                year_org_tvalue_dict[k][org_id] = len(persons) / len(set(persons))
            except ZeroDivisionError:
                year_org_tvalue_dict[k][org_id] = 0
    for k, v in year_org_tvalue_dict.items():
        t_value_list = [x for x in v.values() if x > 0]
        min_t = min(t_value_list)
        max_t = max(t_value_list)
        for k1, v1 in v.items():
            try:
                oindex_tight = round(max(2, 10 * (v1 - min_t) / (max_t - min_t)), 2)
            except ZeroDivisionError:
                oindex_tight = 10
            for item in radar_dict[k1]:
                if k == item["year"]:
                    item.update({"oindex_tight": oindex_tight})

    for k, v in radar_dict.items():
        for item in v:
            if "oindex_tight" not in item:
                item.update({"oindex_tight": 0})
    return radar_dict


def update_hdt(radar_dict):
    """
    更新高度、深度、紧密度
    """
    update_list = []
    for k, v in radar_dict.items():
        org_oindex_info = institution_col.find_one({"_id": k}, {"oindex": 1})
        oindex_list = org_oindex_info.get("oindex")
        oindex_year = [x["year"] for x in oindex_list]
        if v[0]["year"] in oindex_year:
            update_list.append(
                UpdateOne({"_id": k, "oindex.year": v[0]["year"]}, {"$pull": {"oindex": {"year": v[0]["year"]}}}))
            update_list.append(UpdateOne({"_id": k}, {"$push": {"oindex": v[0]}}))
        else:
            update_list.append(UpdateOne({"_id": k}, {"$push": {"oindex": v[0]}}))
    if update_list:
        institution_col.bulk_write(update_list)


def update_oindex_bread(org_list, year):
    """
    更新广度
    """
    update_list = []
    institution_data = institution_col.find({"_id": {"$in": org_list}})

    for item in institution_data:
        ration_info = col_top11.aggregate([{"$match": {"dept_id": str(item["_id"]), "year": int(year)}},
                                           {"$group":{"_id":"$dept_id","ration":{"$sum":"$ration"}}}])
        ration_info = list(ration_info)

        ration = ration_info[0]["ration"]*100
        if ration >= 95:
            oindex_bread = 10
        elif ration >= 85:
            oindex_bread = 9
        elif ration >= 75:
            oindex_bread = 8
        elif ration >= 65:
            oindex_bread = 7
        elif ration >= 55:
            oindex_bread = 6
        elif ration >= 45:
            oindex_bread = 5
        elif ration >= 35:
            oindex_bread = 4
        elif ration >= 25:
            oindex_bread = 3
        elif ration >= 15:
            oindex_bread = 2
        elif ration >= 5:
            oindex_bread = 1
        else:
            oindex_bread = 0
        update_list.append(
            UpdateOne(
                {"_id": item["_id"], "oindex.year": year}, {"$set": {"oindex.$.oindex_bread": oindex_bread}}
            )
        )
    if update_list:
        institution_col.bulk_write(update_list)


def generate_org_year_activity_dict(_query_year, org_list):
    org_year_activity_dict = {}
    for org in org_list:
        activity_data = activity_col.find(
            {"$or": [{"institution_id": org}, {"co_inst_ids": org}], **_query_year}, {"end_time": 1}
        )
        activity_data = list(activity_data)
        year_activity_dict = defaultdict(list)
        for item in activity_data:
            year_activity_dict[item["end_time"].year].append(item["_id"])
        org_year_activity_dict[org] = year_activity_dict
    return org_year_activity_dict


def generate_activity_location_dict(_query_year, province_area_dict):
    activity_location_dict = {}
    activity_data = activity_col.find(_query_year, {"region": 1})
    for item in activity_data:
        if item.get("region", {}):
            activity_province = item.get("region", {}).get("province", "")
            activity_city = item.get("region", {}).get("city", "")
            activity_area = province_area_dict[activity_province]
        else:
            activity_province = ""
            activity_city = ""
            activity_area = ""
        activity_location_dict[item["_id"]] = {
            "area": activity_area,
            "city": activity_city,
            "province": activity_province,
        }
    return activity_location_dict


def update_alumni_score():
    """
    rank_alumni_score:活跃度排名
    prank_alumni_score:后阅读排名百分比
    alumni_score:活跃度
    """
    person_role_score = defaultdict(lambda: 1)
    person_role_score.update(
        {"一般参与": 1, "中等参加": 2, "深度参与": 3, "": 1, None: 1, "中等参与": 2, "中度参与": 2})
    activity_role_score = defaultdict(lambda: 1)
    activity_role_score.update({"常规": 1, "重点": 2, "重大": 3, "": 1, None: 1})

    def cal_identity_value(person_id):
        act_reg = activity_register_col.find({"person_id": ObjectId(person_id)})
        act_reg = list(act_reg)
        activity_id__rolescore_dict = {x["activity_id"]: person_role_score[x.get("level_of_role")] for x in act_reg}
        act_ids = [x["activity_id"] for x in act_reg]
        activity_data = activity_col.find({"_id": {"$in": act_ids}})
        activity_data = list(activity_data)
        activity_id_score_dict = {
            x["_id"]: activity_role_score[x.get("importance_of_activities")] for x in activity_data
        }
        score = 0
        for k, v in activity_id__rolescore_dict.items():
            score += v * activity_id_score_dict[k]
        return score

    person_score_dict = {}
    person_ids = activity_register_col.find({"is_attended": True}, {"person_id": 1}).distinct("person_id")
    for person in tqdm(person_ids):
        person_score_dict[person] = cal_identity_value(person)

    score_list = list(person_score_dict.values())
    score_list.sort(reverse=True)

    person_identity_rank_dict = {}
    person_identity_p_rank_dict = {}
    update_list = []
    for k, v in person_score_dict.items():
        person_identity_rank_dict[k] = score_list.index(v) + 1
        person_identity_p_rank_dict[k] = math.ceil(score_list.index(v) / len(score_list) * 100)
        # rank_alumni_score  排第几名，prank_alumni_score  排名百分比  alumni_score 活跃度
        update_list.append(
            UpdateOne(
                {"_id": k},
                {
                    "$set": {
                        "rank_alumni_score": score_list.index(v) + 1,
                        "prank_alumni_score": math.ceil(score_list.index(v) / len(score_list) * 100),
                        "alumni_score": person_score_dict[k],
                    }
                },
            )
        )
    if update_list:
        col_person.bulk_write(update_list)


def update_oindex_multi(org_year_activity_dict, activity_location_dict):
    """
    活动举办地对应四大区域（即东部地区、中部地区、西部地区、东北地区）。
    统计科协内部机构，年度组织的活动所在省份城市和对应的四大区域中的哪些区域。
    """
    update_list = []
    for org_id, year_act_dict in org_year_activity_dict.items():
        for k, v in year_act_dict.items():
            activity_area = [activity_location_dict[x].get("area") for x in v]
            activity_area = [x for x in activity_area if x]
            activity_area = list(set(activity_area))
            if len(activity_area) >= 3:
                update_list.append(
                    UpdateOne({"_id": org_id, "oindex.year": k}, {"$set": {"oindex.$.oindex_multi": 10}})
                )
            elif len(activity_area) >= 2:
                update_list.append(UpdateOne({"_id": org_id, "oindex.year": k}, {"$set": {"oindex.$.oindex_multi": 9}}))
            else:
                activity_num = len(v)
                activity_province = [activity_location_dict[x].get("province") for x in v]
                activity_province = [x for x in activity_province if x]
                activity_province = list(set(activity_province))
                activity_city = [activity_location_dict[x].get("city") for x in v]
                activity_city = [x for x in activity_city if x]
                activity_city = list(set(activity_city))
                if len(activity_province) >= 2 or len(activity_city) >= 2:
                    update_list.append(
                        UpdateOne({"_id": org_id, "oindex.year": 2023}, {"$set": {"oindex.$.oindex_multi": 8}})
                    )
                elif activity_num >= 2:
                    update_list.append(
                        UpdateOne({"_id": org_id, "oindex.year": 2023}, {"$set": {"oindex.$.oindex_multi": 6}})
                    )
                else:
                    update_list.append(
                        UpdateOne({"_id": org_id, "oindex.year": 2023}, {"$set": {"oindex.$.oindex_multi": 2}})
                    )
    if update_list:
        res = institution_col.bulk_write(update_list)


def set_default_value(org_list):
    """
    雷达图没有更的设置默认值
    """
    update_list = []
    institution_data = institution_col.find({"_id": {"$in": org_list}})
    for item in institution_data:
        for item2 in item["oindex"]:
            if not item2.get("oindex_high"):
                update_list.append(
                    UpdateOne({"_id": item["_id"], "oindex.year": item2["year"]}, {"$set": {"oindex.$.oindex_high": 0}})
                )
            if not item2.get("oindex_deep"):
                update_list.append(
                    UpdateOne({"_id": item["_id"], "oindex.year": item2["year"]}, {"$set": {"oindex.$.oindex_deep": 0}})
                )
            if not item2.get("oindex_tight"):
                update_list.append(
                    UpdateOne({"_id": item["_id"], "oindex.year": item2["year"]},
                              {"$set": {"oindex.$.oindex_tight": 0}})
                )
            if not item2.get("oindex_bread"):
                update_list.append(
                    UpdateOne({"_id": item["_id"], "oindex.year": item2["year"]},
                              {"$set": {"oindex.$.oindex_bread": 0}})
                )
            if not item2.get("oindex_multi"):
                update_list.append(
                    UpdateOne({"_id": item["_id"], "oindex.year": item2["year"]},
                              {"$set": {"oindex.$.oindex_multi": 0}})
                )
    if update_list:
        res = institution_col.bulk_write(update_list)


def task_radar(start_year: int = None, end_year: int = None):
    _query_year = {"end_time": query_year(start_year, end_year)}

    org_list = [
        ObjectId("62b945cd9aebef53937fecc0"),
        ObjectId("62b945cd9aebef53937fecc1"),
        ObjectId("62b945cd9aebef53937fecc2"),
        ObjectId("62b945cd9aebef53937fecc4"),
        ObjectId("62b945cd9aebef53937fecc5"),
        ObjectId("62b945cd9aebef53937fecc6"),
        ObjectId("62b945cd9aebef53937fecc7"),
        ObjectId("62b945cd9aebef53937fecc8"),
        ObjectId("62b945cd9aebef53937fecc9"),
        ObjectId("62b945cd9aebef53937fecca"),
        ObjectId("62b945cd9aebef53937feccb"),
    ]

    position = ["教授", "研究员", "主任医师", "编审", "高级记者", "高级编辑", "一级律师", "研究馆员", "院士",
                "正高级经济师", "正高级工程师", "正高级教师"]

    mapping_region = {
        "东部地区": ["北京市", "天津市", "河北省", "上海市", "江苏", "浙江省", "福建省", "山东省", "广东省", "海南省"],
        "中部地区": ["山西省", "安徽省", "江西省", "河南省", "湖北省", "湖南省"],
        "西部地区": ["内蒙古自治区", "广西壮族自治区", "重庆市", "四川省", "贵州省", "云南省", "西藏自治区", "陕西省",
                     "甘肃省", "青海省", "宁夏回族自治区", "新疆维吾尔自治区"],
        "东北地区": ["辽宁省", "吉林省", "黑龙江省"],
    }
    province_area_dict = defaultdict(str)
    for k, v in mapping_region.items():
        for province in v:
            province_area_dict[province] = k

    person_position_dict = generate_person_position_dict()
    org_year_activity_dict = generate_org_year_activity_dict(_query_year, org_list)
    activity_location_dict = generate_activity_location_dict(_query_year, province_area_dict)

    radar_dict = cal_oindex_high(person_position_dict, org_year_activity_dict, org_list, position)
    radar_dict = cal_oindex_deep(radar_dict, org_year_activity_dict)
    radar_dict = cal_oindex_tight(radar_dict, org_year_activity_dict)
    update_hdt(radar_dict)
    update_oindex_bread(org_list, start_year)
    update_oindex_multi(org_year_activity_dict, activity_location_dict)
    set_default_value(org_list)


if __name__ == "__main__":
    t = time.time()
    task_radar(start_year=2022)
    task_radar(start_year=2023)
    print(time.time() - t)
